#include "../../include/helpers/canvas_render_objects.h"
#include "../../include/helpers/general.h"
#include <memory>
#include <vector>

namespace ohos_rive {
// RIVE RGBA 转换为 OHOS ARGB
uint32_t RiveColorToOhosColor(rive::ColorInt color)
{
    uint32_t r = (color >> 24) & 0xFF;
    uint32_t g = (color >> 16) & 0xFF;
    uint32_t b = (color >> 8) & 0xFF;
    uint32_t a = color & 0xFF;
    return (a << 24) | (r << 16) | (g << 8) | b;
}

OH_Drawing_Matrix *RiveMatrixToOhosMatrix(const rive::Mat2D &matrix)
{
    auto ohosMatrix = OH_Drawing_MatrixCreate();
    OH_Drawing_MatrixSetMatrix(ohosMatrix, matrix.xx(), matrix.xy(), matrix.tx(), matrix.yx(), matrix.yy(), matrix.ty(),
                               0, 0, 1);
    return ohosMatrix;
}

OH_Drawing_BlendMode RiveBlendModeToOhosBlendMode(rive::BlendMode value)
{
    OH_Drawing_BlendMode blendMode;
    switch (value) {
        case rive::BlendMode::srcOver:
            blendMode = BLEND_MODE_SRC_OVER;
            break;
        case rive::BlendMode::screen:
            blendMode = BLEND_MODE_SCREEN;
            break;
        case rive::BlendMode::overlay:
            blendMode = BLEND_MODE_OVERLAY;
            break;
        case rive::BlendMode::darken:
            blendMode = BLEND_MODE_DARKEN;
            break;
        case rive::BlendMode::lighten:
            blendMode = BLEND_MODE_LIGHTEN;
            break;
        case rive::BlendMode::colorDodge:
            blendMode = BLEND_MODE_COLOR_DODGE;
            break;
        case rive::BlendMode::colorBurn:
            blendMode = BLEND_MODE_COLOR_BURN;
            break;
        case rive::BlendMode::hardLight:
            blendMode = BLEND_MODE_HARD_LIGHT;
            break;
        case rive::BlendMode::softLight:
            blendMode = BLEND_MODE_SOFT_LIGHT;
            break;
        case rive::BlendMode::difference:
            blendMode = BLEND_MODE_DIFFERENCE;
            break;
        case rive::BlendMode::exclusion:
            blendMode = BLEND_MODE_EXCLUSION;
            break;
        case rive::BlendMode::multiply:
            blendMode = BLEND_MODE_MULTIPLY;
            break;
        case rive::BlendMode::hue:
            blendMode = BLEND_MODE_HUE;
            break;
        case rive::BlendMode::saturation:
            blendMode = BLEND_MODE_SATURATION;
            break;
        case rive::BlendMode::color:
            blendMode = BLEND_MODE_COLOR;
            break;
        case rive::BlendMode::luminosity:
            blendMode = BLEND_MODE_LUMINOSITY;
            break;
        default:
            blendMode = BLEND_MODE_SRC_OVER;
            break;
    }
    return blendMode;
}

OH_Drawing_Bitmap *ConvertPixelMapToBitmap(OH_PixelmapNative *nativePixelMap)
{
    if (nativePixelMap == nullptr) {
        return nullptr;
    }

    // 1. 获取 PixelMap 的宽高信息
    uint32_t width, height;
    OH_Pixelmap_ImageInfo *imageInfo;
    OH_PixelmapImageInfo_Create(&imageInfo);
    auto result = OH_PixelmapNative_GetImageInfo(nativePixelMap, imageInfo);
    if (result != IMAGE_SUCCESS) {
        OH_PixelmapImageInfo_Release(imageInfo);
        return nullptr;
    }
    OH_PixelmapImageInfo_GetWidth(imageInfo, &width);
    OH_PixelmapImageInfo_GetHeight(imageInfo, &height);
    OH_PixelmapImageInfo_Release(imageInfo);

    // 2. 创建 Bitmap 对象
    OH_Drawing_Bitmap *bitmap = OH_Drawing_BitmapCreate();
    if (bitmap == NULL) {
        return NULL;
    }

    // 3. 配置 Bitmap 宽高和像素格式
    OH_Drawing_BitmapFormat bitmapFormat = {.colorFormat = COLOR_FORMAT_RGBA_8888, .alphaFormat = ALPHA_FORMAT_PREMUL};

    OH_Drawing_BitmapBuild(bitmap, width, height, &bitmapFormat);

    // 4. 创建 Canvas 并绑定到 Bitmap
    OH_Drawing_Canvas *canvas = OH_Drawing_CanvasCreate();
    if (canvas == NULL) {
        OH_Drawing_BitmapDestroy(bitmap);
        return NULL;
    }
    OH_Drawing_CanvasBind(canvas, bitmap);

    // 5. 设置源矩形和目标矩形
    OH_Drawing_Rect *srcRect = OH_Drawing_RectCreate(0, 0, width, height);
    OH_Drawing_Rect *dstRect = OH_Drawing_RectCreate(0, 0, width, height);

    // 6. 设置采样选项
    auto samplingOpts = OH_Drawing_SamplingOptionsCreate(FILTER_MODE_LINEAR, MIPMAP_MODE_NONE);

    // 7. 将 PixelMap 绘制到 Canvas（即绘制到 Bitmap）
    OH_Drawing_PixelMap *pixelMap = OH_Drawing_PixelMapGetFromOhPixelMapNative(nativePixelMap);
    OH_Drawing_CanvasDrawPixelMapRect(canvas, pixelMap, srcRect, dstRect, samplingOpts);

    // 8. 释放 Canvas 资源
    OH_Drawing_CanvasDestroy(canvas);

    // 返回转换后的 Bitmap
    return bitmap;
}

/** CanvasRenderPath */
/* static */ OH_Drawing_Path *CanvasRenderPath::CreatePath()
{
    auto path = OH_Drawing_PathCreate();
    if (path == nullptr) {
        LOGE("Failed to create OHOS Drawing Path");
    }
    return path;
}

CanvasRenderPath::CanvasRenderPath() : m_FillRule(rive::FillRule::nonZero), m_ohosPath(CreatePath())
{
    LOGD("CanvasRenderPath created");
}

static void addRawPathToCanvasPath(OH_Drawing_Path *ohosPath, const rive::RawPath &path)
{
    if (!ohosPath) {
        LOGE("addRawPathToCanvasPath: null path");
        return;
    }

    auto points = path.points();
    auto pointsData = points.data();
    auto pathVerbs = path.verbs();

    for (auto verb : pathVerbs) {
        switch (verb) {
            case rive::PathVerb::move: {
                auto point = pointsData[0];
                OH_Drawing_PathMoveTo(ohosPath, point.x, point.y);
                pointsData += 1;
                break;
            }
            case rive::PathVerb::line: {
                auto point = pointsData[0];
                OH_Drawing_PathLineTo(ohosPath, point.x, point.y);
                pointsData += 1;
                break;
            }
            case rive::PathVerb::cubic: {
                auto cp0 = pointsData[0];
                auto cp1 = pointsData[1];
                auto to = pointsData[2];
                OH_Drawing_PathCubicTo(ohosPath, cp0.x, cp0.y, cp1.x, cp1.y, to.x, to.y);
                pointsData += 3;
                break;
            }
            case rive::PathVerb::close: {
                OH_Drawing_PathClose(ohosPath);
                break;
            }
            default:
                LOGW("Unknown path verb: %d", static_cast<int>(verb));
                break;
        }
    }
}

CanvasRenderPath::CanvasRenderPath(rive::RawPath &path, rive::FillRule rule)
    : m_FillRule(rule), m_ohosPath(CreatePath())
{
    addRawPathToCanvasPath(m_ohosPath, path);
    LOGD("CanvasRenderPath created from RawPath");
}

CanvasRenderPath::~CanvasRenderPath()
{
    OH_Drawing_PathDestroy(m_ohosPath);
    LOGD("CanvasRenderPath destroyed");
}

void CanvasRenderPath::rewind()
{
    if (m_ohosPath) {
        OH_Drawing_PathReset(m_ohosPath);
    }
}

void CanvasRenderPath::addRawPath(const rive::RawPath &path)
{
    addRawPathToCanvasPath(m_ohosPath, path);
}

void CanvasRenderPath::addRenderPath(rive::RenderPath *path, const rive::Mat2D &transform)
{
    if (!path || !m_ohosPath) {
        LOGE("addRenderPath: invalid parameters");
        return;
    }

    auto otherPath = reinterpret_cast<CanvasRenderPath *>(path);
    if (!otherPath->m_ohosPath) {
        LOGE("addRenderPath: other path is null");
        return;
    }

    // 创建变换矩阵并添加路径
    auto matrix = RiveMatrixToOhosMatrix(transform);
    OH_Drawing_PathAddPath(m_ohosPath, otherPath->m_ohosPath, matrix);
}

void CanvasRenderPath::moveTo(float x, float y)
{
    if (m_ohosPath) {
        OH_Drawing_PathMoveTo(m_ohosPath, x, y);
    }
}

void CanvasRenderPath::lineTo(float x, float y)
{
    if (m_ohosPath) {
        OH_Drawing_PathLineTo(m_ohosPath, x, y);
    }
}

void CanvasRenderPath::cubicTo(float ox, float oy, float ix, float iy, float x, float y)
{
    if (m_ohosPath) {
        OH_Drawing_PathCubicTo(m_ohosPath, ox, oy, ix, iy, x, y);
    }
}

void CanvasRenderPath::close()
{
    if (m_ohosPath) {
        OH_Drawing_PathClose(m_ohosPath);
    }
}

void CanvasRenderPath::fillRule(rive::FillRule value)
{
    m_FillRule = value;
    if (!m_ohosPath) {
        return;
    }

    OH_Drawing_PathFillType fillType;
    switch (m_FillRule) {
        case rive::FillRule::evenOdd:
            fillType = PATH_FILL_TYPE_EVEN_ODD;
            break;
        case rive::FillRule::nonZero:
        case rive::FillRule::clockwise:
        default:
            fillType = PATH_FILL_TYPE_WINDING;
            break;
    }

    OH_Drawing_PathSetFillType(m_ohosPath, fillType);
}

/** LinearGradientCanvasShader */
LinearGradientCanvasShader::LinearGradientCanvasShader(float sx,
                                                       float sy,
                                                       float ex,
                                                       float ey,
                                                       const rive::ColorInt colors[], // [count]
                                                       const float stops[],           // [count]
                                                       size_t count)
{
    if (count == 0 || !colors || !stops) {
        LOGE("LinearGradientCanvasShader: invalid parameters");
        return;
    }

    // 创建颜色数组
    std::vector<uint32_t> colorsVec;
    colorsVec.reserve(count);
    for (size_t i = 0; i < count; ++i) {
        colorsVec.emplace_back(RiveColorToOhosColor(colors[i]));
    }

    // 创建渐变着色器
    m_OhosShader = OH_Drawing_ShaderEffectCreateLinearGradient(
        OH_Drawing_PointCreate(sx, sy), OH_Drawing_PointCreate(ex, ey), colorsVec.data(), stops, count, CLAMP);

    if (m_OhosShader == nullptr) {
        LOGE("Failed to create LinearGradientCanvasShader");
    } else {
        LOGD("LinearGradientCanvasShader created successfully");
    }
}

/** RadialGradientCanvasShader */
RadialGradientCanvasShader::RadialGradientCanvasShader(float cx,
                                                       float cy,
                                                       float radius,
                                                       const rive::ColorInt colors[], // [count]
                                                       const float stops[],           // [count]
                                                       size_t count)
{
    if (count == 0 || !colors || !stops) {
        LOGE("RadialGradientCanvasShader: invalid parameters");
        return;
    }

    // 创建颜色数组
    std::vector<uint32_t> colorsVec;
    colorsVec.reserve(count);
    for (size_t i = 0; i < count; ++i) {
        colorsVec.emplace_back(RiveColorToOhosColor(colors[i]));
    }

    // 创建径向渐变着色器
    m_OhosShader = OH_Drawing_ShaderEffectCreateRadialGradient(OH_Drawing_PointCreate(cx, cy), radius, colorsVec.data(),
                                                               stops, count, CLAMP);

    if (m_OhosShader == nullptr) {
        LOGE("Failed to create RadialGradientCanvasShader");
    } else {
        LOGD("RadialGradientCanvasShader created successfully");
    }
}

/** CanvasRenderPaint */
CanvasRenderPaint::CanvasRenderPaint()
{
    m_ohPaint = new OhosPaint();
    if (m_ohPaint == nullptr) {
        LOGE("Failed to create OhosPaint");
        return;
    }
    // Default Fill Mode
    m_ohPaint->brush = OH_Drawing_BrushCreate();
    if (m_ohPaint->brush == nullptr) {
        LOGE("Failed to create Brush");
        return;
    }
    OH_Drawing_BrushSetAntiAlias(m_ohPaint->brush, true);
    LOGD("CanvasRenderPaint created successfully");
}

CanvasRenderPaint::~CanvasRenderPaint()
{
    if (m_ohPaint->style == OhosPaint::PaintStyle::stroke) {
        OH_Drawing_PenDestroy(m_ohPaint->pen);
    } else {
        OH_Drawing_BrushDestroy(m_ohPaint->brush);
    }
    delete m_ohPaint;
    LOGD("CanvasRenderPaint destroyed");
}

void CanvasRenderPaint::style(rive::RenderPaintStyle style)
{
    SetStyle(m_ohPaint, style);
}

void CanvasRenderPaint::thickness(float value)
{
    SetThickness(m_ohPaint, value);
}

void CanvasRenderPaint::join(rive::StrokeJoin join)
{
    SetJoin(m_ohPaint, join);
}

void CanvasRenderPaint::color(rive::ColorInt value)
{
    SetColor(m_ohPaint, value);
}

void CanvasRenderPaint::cap(rive::StrokeCap cap)
{
    SetCap(m_ohPaint, cap);
}

void CanvasRenderPaint::shader(rive::rcp<rive::RenderShader> shader)
{
    // `shader` can also be a `nullptr`.
    OH_Drawing_ShaderEffect *shaderObject =
        shader == nullptr ? nullptr : reinterpret_cast<CanvasShader *>(shader.get())->ohosShader();
    SetShader(m_ohPaint, shaderObject);
}

void CanvasRenderPaint::blendMode(rive::BlendMode blendMode)
{
    SetBlendMode(m_ohPaint, blendMode);
}

/* static */ void CanvasRenderPaint::SetStyle(OhosPaint *paint, rive::RenderPaintStyle style)
{
    if (style == rive::RenderPaintStyle::stroke) {
        if (paint->style == OhosPaint::PaintStyle::stroke) {
            return;
        }
        paint->style = OhosPaint::PaintStyle::stroke;

        if (!paint->brush) {
            OH_Drawing_BrushDestroy(paint->brush);
            paint->brush = nullptr;
        }

        paint->pen = OH_Drawing_PenCreate();
        OH_Drawing_PenSetAntiAlias(paint->pen, true);
    } else {
        if (paint->style == OhosPaint::PaintStyle::fill) {
            return;
        }
        paint->style = OhosPaint::PaintStyle::fill;

        if (!paint->pen) {
            OH_Drawing_PenDestroy(paint->pen);
            paint->pen = nullptr;
        }

        paint->brush = OH_Drawing_BrushCreate();
        OH_Drawing_BrushSetAntiAlias(paint->brush, true);
    }
}

/* static */ void CanvasRenderPaint::SetThickness(OhosPaint *paint, float value)
{
    if (paint->style != OhosPaint::PaintStyle::stroke || paint->pen == nullptr) {
        LOGE("Set thickness error: style error");
        return;
    }
    OH_Drawing_PenSetWidth(paint->pen, value);
}

/* static */ void CanvasRenderPaint::SetJoin(OhosPaint *paint, rive::StrokeJoin value)
{
    if (paint->style != OhosPaint::PaintStyle::stroke || paint->pen == nullptr) {
        LOGE("Set join error: style error");
        return;
    }

    OH_Drawing_PenLineJoinStyle joinStyle;
    switch (value) {
        case rive::StrokeJoin::round:
            joinStyle = LINE_ROUND_JOIN;
            break;
        case rive::StrokeJoin::bevel:
            joinStyle = LINE_BEVEL_JOIN;
            break;
        default:
        case rive::StrokeJoin::miter:
            joinStyle = LINE_MITER_JOIN;
            break;
    }

    OH_Drawing_PenSetJoin(paint->pen, joinStyle);
}

/* static */ void CanvasRenderPaint::SetColor(OhosPaint *paint, rive::ColorInt value)
{
    if (paint->style == OhosPaint::PaintStyle::stroke && paint->pen != nullptr) {
        OH_Drawing_PenSetColor(paint->pen, RiveColorToOhosColor(value));
    } else if (paint->style == OhosPaint::PaintStyle::fill && paint->brush != nullptr) {
        OH_Drawing_BrushSetColor(paint->brush, RiveColorToOhosColor(value));
    } else {
        LOGE("Set Color error: style mismatch");
    }
}

/* static */ void CanvasRenderPaint::SetCap(OhosPaint *paint, rive::StrokeCap value)
{
    if (paint->style != OhosPaint::PaintStyle::stroke || paint->pen == nullptr) {
        LOGE("Set cap error: style error");
        return;
    }
    OH_Drawing_PenLineCapStyle capStyle;
    switch (value) {
        case rive::StrokeCap::butt:
            capStyle = LINE_FLAT_CAP;
            break;
        case rive::StrokeCap::round:
            capStyle = LINE_ROUND_CAP;
            break;
        case rive::StrokeCap::square:
            capStyle = LINE_SQUARE_CAP;
            break;
        default:
            capStyle = LINE_FLAT_CAP;
            break;
    }
    OH_Drawing_PenSetCap(paint->pen, capStyle);
}

/* static */ void CanvasRenderPaint::SetShader(OhosPaint *paint, OH_Drawing_ShaderEffect *shader)
{
    if (paint->style == OhosPaint::PaintStyle::stroke && paint->pen != nullptr) {
        OH_Drawing_PenSetShaderEffect(paint->pen, shader);
    } else if (paint->style == OhosPaint::PaintStyle::fill && paint->brush != nullptr) {
        OH_Drawing_BrushSetShaderEffect(paint->brush, shader);
    } else {
        LOGE("Set Shader error: style mismatch");
    }
}

/* static */ OhosPaint *CanvasRenderPaint::CreateOhosPaint()
{
    auto ohPaint = new OhosPaint();
    // Default Fill Mode
    ohPaint->brush = OH_Drawing_BrushCreate();
    if (ohPaint->brush == nullptr) {
        LOGE("Failed to create Brush");
        return nullptr;
    }
    OH_Drawing_BrushSetAntiAlias(ohPaint->brush, true);
    LOGD("CanvasRenderPaint created successfully");

    return ohPaint;
}

/* static */ void CanvasRenderPaint::SetBlendMode(OhosPaint *paint, rive::BlendMode value)
{
    auto blendMode = RiveBlendModeToOhosBlendMode(value);
    if (paint->style == OhosPaint::PaintStyle::stroke && paint->pen != nullptr) {
        OH_Drawing_PenSetBlendMode(paint->pen, blendMode);
    } else if (paint->style == OhosPaint::PaintStyle::fill && paint->brush != nullptr) {
        OH_Drawing_BrushSetBlendMode(paint->brush, blendMode);
    } else {
        LOGE("Set Blend Mode error: style mismatch");
    }
}

/* static */ void CanvasRenderPaint::SetPaintAlpha(OhosPaint *paint, int alpha)
{
    if (paint->style == OhosPaint::PaintStyle::stroke && paint->pen != nullptr) {
        OH_Drawing_PenSetAlpha(paint->pen, alpha);
    } else if (paint->style == OhosPaint::PaintStyle::fill && paint->brush != nullptr) {
        OH_Drawing_BrushSetAlpha(paint->brush, alpha);
    } else {
        LOGE("Set Alpha error: style mismatch");
    }
}

/* CanvasRenderImage */
/* static */ OH_Drawing_Bitmap *CanvasRenderImage::CreateBitmapFrom(rive::Span<const uint8_t> &encodedBytes)
{
    OH_ImageSourceNative *imageSource = nullptr;
    std::unique_ptr<uint8_t[]> buffer(new uint8_t[encodedBytes.size()]);
    memcpy(buffer.get(), encodedBytes.data(), encodedBytes.size());
    auto result = OH_ImageSourceNative_CreateFromData(buffer.get(), encodedBytes.size(), &imageSource);
    if (result != IMAGE_SUCCESS || imageSource == nullptr) {
        LOGE("CreateBitmapFrom() - Failed to create ImageSourceNative.");
        return nullptr;
    }

    OH_DecodingOptions *decodingOptions = nullptr;
    result = OH_DecodingOptions_Create(&decodingOptions);
    if (result != IMAGE_SUCCESS || decodingOptions == nullptr) {
        LOGE("CreateBitmapFrom() - Failed to create Decoding Options.");
        OH_ImageSourceNative_Release(imageSource);
        return nullptr;
    }

    OH_PixelmapNative *pixelmap = nullptr;
    result = OH_ImageSourceNative_CreatePixelmap(imageSource, decodingOptions, &pixelmap);
    OH_DecodingOptions_Release(decodingOptions);
    OH_ImageSourceNative_Release(imageSource);
    if (result != IMAGE_SUCCESS || pixelmap == nullptr) {
        LOGE("CreateBitmapFrom() - Failed to create Pixel Map.");
        return nullptr;
    }
    auto bitmap = ConvertPixelMapToBitmap(pixelmap);
    OH_PixelmapNative_Release(pixelmap);
    return bitmap;
}

CanvasRenderImage::CanvasRenderImage(rive::Span<const uint8_t> encodedBytes)
{
    m_ohosBitmap = CreateBitmapFrom(encodedBytes);
    if (m_ohosBitmap == nullptr) {
        LOGE("CanvasRenderImage() - Failed to create a bitmap.");
        return;
    }
    m_Width = OH_Drawing_BitmapGetWidth(m_ohosBitmap);
    m_Height = OH_Drawing_BitmapGetHeight(m_ohosBitmap);

    m_ohosPaint = CanvasRenderPaint::CreateOhosPaint();
}

CanvasRenderImage::CanvasRenderImage(OH_PixelmapNative *pixelMap)
{
    if (pixelMap == nullptr) {
        LOGE("CanvasRenderImage(jBitmap) - pixelMap is null.");
        return;
    }

    m_ohosBitmap = ConvertPixelMapToBitmap(pixelMap);
    OH_PixelmapNative_Release(pixelMap);
    m_Width = OH_Drawing_BitmapGetWidth(m_ohosBitmap);
    m_Height = OH_Drawing_BitmapGetHeight(m_ohosBitmap);

    m_ohosPaint = CanvasRenderPaint::CreateOhosPaint();
}

CanvasRenderImage::~CanvasRenderImage()
{
    if (m_ohosBitmap) {
        OH_Drawing_BitmapDestroy(m_ohosBitmap);
        m_ohosBitmap = nullptr;
    }
    if (m_ohosPaint) {
        if (m_ohosPaint->pen) {
            OH_Drawing_PenDestroy(m_ohosPaint->pen);
        }
        if (m_ohosPaint->brush) {
            OH_Drawing_BrushDestroy(m_ohosPaint->brush);
        }

        delete m_ohosPaint;
    }
}

/* static */ OH_Drawing_ShaderEffect *CanvasRenderImage::CreateBitmapShader(OH_Drawing_Bitmap *bitmap)
{
    if (!bitmap) {
        LOGE("CreateBitmapShader: null bitmap");
        return nullptr;
    }

    auto image = OH_Drawing_ImageCreate();
    auto result = OH_Drawing_ImageBuildFromBitmap(image, bitmap);
    if (!result) {
        LOGE("CreateBitmapShader: Image Build From Bitmap failed");
        return nullptr;
    }

    OH_Drawing_SamplingOptions *samplingOptions =
        OH_Drawing_SamplingOptionsCreate(FILTER_MODE_LINEAR, MIPMAP_MODE_NONE);

    // 4. 从Image创建shader，设置平铺模式
    OH_Drawing_ShaderEffect *shader = OH_Drawing_ShaderEffectCreateImageShader(image,           // 从bitmap转换来的image
                                                                               CLAMP,           // x方向平铺模式
                                                                               CLAMP,           // y方向平铺模式
                                                                               samplingOptions, // 采样选项
                                                                               nullptr          // 使用默认矩阵
    );
    if (shader == nullptr) {
        LOGE("Failed to create bitmap shader");
    }

    OH_Drawing_SamplingOptionsDestroy(samplingOptions);
    OH_Drawing_ImageDestroy(image);
    return shader;
}

} // namespace ohos_rive